home *** CD-ROM | disk | FTP | other *** search
/ Aminet 5 / Aminet 5 - March 1995.iso / Aminet / gfx / show / PhotoCDAGA10.lha / PhotoCDAGA / developer / EncodeHAM.asm next >
Assembly Source File  |  1994-04-19  |  19KB  |  449 lines

  1. ; ppm2AGA utility functions written by Günther Röhrich
  2.  
  3. ; the version for 68020+ processors is slightly faster and smaller
  4. ; the function is called from C:
  5. ; EncodeHAM(char *yorig, char *yham, char *ColorTable,
  6. ;            short NumColors, short xsize);
  7. ; yorig       = original row in rgbrgb... format
  8. ; yham        = row in HAM chunky format
  9. ; ColorTable  = color table in brgbrg... format
  10. ; NumColors   = (number of valid colors in ColorTable)*3
  11. ; xsize       = size of row in pixels
  12. ; ConvertMode should contain: 0 for HAM6 encoding
  13. ;                             1 for HAM8 encoding
  14.  
  15. ; int MapColor(colorhist_vector colormap, pixval r1, pixval g1, pixval b1,
  16. ;              int NumColors) 
  17. ; see later
  18.  
  19.  
  20.     IFD MC68020
  21.       MACHINE MC68020
  22.     ENDC
  23.  
  24.     IFD MC68000
  25.       MACHINE MC68000
  26.     ENDC
  27.  
  28.  
  29. ;NOTE: GCC stores all data as 32 bit at subroutine calls!
  30.  
  31. yorig        EQU 44  ;pointer to actual row (original)
  32. yham         EQU 48  ;pointer to actual row (HAM)
  33. ColorTable   EQU 52  ;address of color table (3 bytes per entry)
  34.  IFD GCC
  35. NumColors    EQU 58
  36. xsize        EQU 62
  37.  ELSE
  38. NumColors    EQU 56  ;number of colors allocated so far (*3)
  39. xsize        EQU 58  ;number of pixels (x)
  40.  ENDC
  41.  
  42. colormap   EQU 44  ;pointer to colorhist_vector
  43.  IFD GCC
  44. r1         EQU 51
  45. g1         EQU 55
  46. b1         EQU 59
  47. NColors    EQU 60
  48.  ELSE
  49. r1         EQU 48  ;red component (byte format)
  50. g1         EQU 50  ;green component
  51. b1         EQU 52  ;blue component
  52. NColors    EQU 54  ;number of colors in colormap
  53.  ENDC
  54.  
  55.     
  56.         XREF _Mult_Table  ;address of multiplication table
  57.         XREF _Mult_Table32
  58.         XREF _ConvertMode        ;HAM8 or HAM6
  59.         XDEF _EncodeHAM  ;entry point for function
  60.         XDEF _MapColorASM
  61.         XREF _ColorCache ;an 256K array
  62.  
  63. *       XDEF _blue_left ;only for debugging purposes
  64. *       XDEF _search_finish ;only for debugging
  65.         XDEF _MaxError
  66.         XDEF _MaxErrorPos 
  67.         XDEF _hit       ;only for debugging
  68.         XDEF _t1        ;only for debugging        
  69.  
  70.                dseg
  71.  
  72.  cnop 0,2
  73. _blue_left:      dc.b 0  ;this order is better for HAM-encoding
  74. _red_left:       dc.b 0
  75. _green_left:     dc.b 0,0 ;additional dummy-value for faster longword access
  76.  
  77.  cnop 0,2
  78. _offset_orig:   dc.w 0
  79. _offset_ham:    dc.w 0
  80. _MaxError:      dc.w 0
  81. _MaxErrorPos    dc.w 0
  82. _CacheOffset    dc.l 0
  83.        
  84.         cseg
  85.  
  86. ;register usage:   D0 = general purpose register
  87. ;                  D1 = contains afterwards the error
  88. ;                  D2 = orig_blue
  89. ;                  D3 = orig_red
  90. ;                  D4 = orig_green
  91. ;                  D5 = color that should be set
  92. ;                  D6 = offset to actual pixel (HAM)
  93. ;                  D7 = offset for color table / (0,1,2) at HAM
  94. ;                  A0 = best color so far (color+1)*3
  95. ;                  A1 = pointer to multiplication table
  96. ;                  A2 = pointer to color table / to _blue_left
  97. ;                  A3 = smallest error that has been reached so far
  98. ;                  A4 = used by the Aztec assembler (small data model)
  99. ;                  A5 = pointer to the actual row (original)
  100. ;                  A6 = pointer to the actual row (HAM)
  101.  
  102. ;WARNING: This will not work with color values higher than 63
  103. ;(HAM8 has a maximum of 63, HAM6 has a maximum of 15)
  104. ;(values higher than 63 may result in memory corruption)
  105.  
  106. ;computing the difference of color values is done with signed 8 bit
  107. ;arithmetic 
  108.  
  109. ;the maximum error value is 63^2+63^2+63^2=11907
  110. ;the summation has to be done therefore with 16 bits
  111.  
  112.  
  113. ;Initializing
  114. _EncodeHAM:     movem.l D2-D7/A2-A3/A5/A6,-(A7)  ;store registers
  115.                 lea     _blue_left,A0      ;load start of left colors
  116.                 move.l  ColorTable(sp),A2
  117.                 IFD MC68020
  118.                   move.l  (A2),(A0)
  119.                 ELSE
  120.                   move.b  (A2)+,(A0)+      ;initialize left colors
  121.                   move.b  (A2)+,(A0)+      ;A2 may not be word aligned
  122.                   move.b  (A2)+,(A0)+
  123.                   lea     -3(A0),A0        ;correct register
  124.                   lea     -3(A2),A2        ;correct register
  125.                 ENDC
  126.                 moveq.l #0,D6              ;initialize ham offset
  127.                 move.l  D6,_MaxError       ;initialize absolute max error
  128.                                            ;and max error pos      
  129.                 move.l  yham(sp),A6                           
  130.                 move.l  yorig(sp),A5
  131.                 lea     _Mult_Table,A1
  132.                 lea     255*2(A1),A1              
  133. search_begin:   move.b  (A5)+,D3           ;load registers with original colors
  134.                 move.b  (A5)+,D4           ;for faster access
  135.                 move.b  (A5)+,D2
  136.         IFD GCC
  137.                  lea     1(A5),A5          ;adjust A5 for correct alignment
  138.                 ENDC                       ;needed for GNU C
  139.                 move.w  #15000,A3          ;dummy-value for minimum error so far
  140.                 move.l  ColorTable(sp),A2
  141.                 moveq.l #0,D7              ;initialize offset for color table
  142.  
  143. ;First take a look if we have the value already in the cache
  144.         moveq.l  #0,D0
  145.                 moveq.l  #0,D1             
  146.                 move.b   D3,D0             ;compute the cache offset
  147.                 lsl.l    #6,D0
  148.                 or.b     D4,D0
  149.                 lsl.l    #6,D0
  150.                 or.b     D2,D0             ;now we have the offset in D0
  151.                 movea.l  _ColorCache,A0    ;load start address of the cache
  152.                 move.b   0(A0,D0.l),D1     ;take the value from the cache
  153.                 bne     _hit               ;jump if we have a cache hit
  154.                 
  155.                 move.l   D0,_CacheOffset   ;store the offset to avoid recomputing it
  156.                 move.l   #3,A0             ;dummy-value for best colornumber so far
  157.                                            ; (3 means color 0)
  158.  
  159. search_start:    bsr      _compute_error
  160.                 cmp.w    D1,A3              ;A3 <= D1 ?
  161.                 bls.s    search4
  162.                 move.w   D1,A3              ;D1 is smaller than A3, store it
  163.                 move.w   D7,A0              ;store color number     
  164.                 tst.w    D1                 ;do we have the correct color ?
  165.                 beq      search5            ;then finish immediately
  166. search4:        cmp.w    NumColors(sp),D7   ;have we reached highest colornum ?
  167.                 bne.s    search_start       ;no, then once again                   
  168.                                         
  169. ;A0 contains now (colornumber+1)*3
  170. ;A3 contains the error for that colornumber
  171.  
  172. _t1:            move.w   A0,D0        
  173.                 movea.l  _ColorCache,A2
  174.                 move.l   _CacheOffset,D1
  175.                 move.b   D0,0(A2,D1.l)      ;store the value in the cache                
  176.                 lea      _blue_left,A2      ;restore A2
  177.  
  178. ;compute the error when using modify mode
  179.  
  180. start_ham6:     move.b   D2,D0              ;load orig_blue
  181.                 moveq.l  #0,D7              ;assume blue should be changed
  182.                 move.b   D2,D5              ;store value to change
  183.                 sub.b    _blue_left,D0      ;D0=D0-_blue_left
  184.                 bpl.s    ham6_1
  185.                 neg.b    D0                 ;make result positive
  186. ham6_1:         move.b   D0,D1              ;store maximum error so far
  187.                 move.b   D3,D0              ;load orig_red
  188.                 sub.b    _red_left,D0       ;D0=D0-_red_left
  189.                 bpl.s    ham6_2
  190.                 neg.b    D0              
  191. ham6_2:         cmp.b    D0,D1              ;check D1-D0
  192.                 bge.s    ham6_3             ;jump if D1>=D0
  193.                 move.b   D0,D1              ;store new maximum error
  194.                 moveq.l  #1,D7              ;assume red should be changed
  195.                 move.b   D3,D5              ;store value to change
  196. ham6_3:         move.b   D4,D0              ;load orig_green
  197.                 sub.b    _green_left,D0     ;D0=D0-_green_left
  198.                 bpl.s    ham6_4
  199.                 neg.b    D0
  200. ham6_4:         cmp.b    D0,D1
  201.                 bge.s    ham6_5
  202.                 move.b   D0,D1              ;store maximum error
  203.                 moveq.l  #2,D7              ;green should be changed
  204.                 move.b   D4,D5              ;store value to change
  205. ham6_5:         lea      _blue_left,A2      
  206.                 move.b   D5,0(A2,D7.W)      ;perform change
  207.  
  208. ham_error:      moveq.l  #0,D1
  209.                 moveq.l  #0,D0
  210.                 move.b   D2,D0              ;load blue_origin
  211.                 sub.b    (A2)+,D0           ;D0 = blue_color - blue_origin
  212.                 ext.w    D0
  213.                 IFD MC68020
  214.                   add.w    0(A1,D0.W*2),D1
  215.                 ELSE
  216.                   add.w    D0,D0            
  217.                   add.w    0(A1,D0.W),D1    ;D1 = D1 + D0*D0
  218.                 ENDC
  219.                 move.b   D3,D0              ;load red_origin
  220.                 sub.b    (A2)+,D0           ;D0 = red_color - red_origin 
  221.                 ext.w    D0
  222.                 IFD MC68020
  223.                   add.w    0(A1,D0.W*2),D1
  224.                 ELSE
  225.                   add.w    D0,D0
  226.                   add.w    0(A1,D0.W),D1
  227.                 ENDC
  228.                 move.b   D4,D0              ;load green_origin
  229.                 sub.b    (A2)+,D0           ;D0 = green_color - green_origin
  230.                 ext.w    D0
  231.                 IFD MC68020
  232.                   add.w    0(A1,D0.W*2),D1
  233.                 ELSE
  234.                   add.w    D0,D0
  235.                   add.w    0(A1,D0.W),D1    ;D1 contains error from HAM encoding
  236.                 ENDC
  237.  
  238.                 cmpa.w   D1,A3              ;check what error is smaller
  239.                 bls.s    _search_finish     ;jump if colortable is better
  240.                 cmp.w    _MaxError,D1       ;compare with absolute max error
  241.                 ble.s    ham6_9             ;jump if _MaxError is greater
  242.                 cmp.w    #2,D6              ;less then 2 pixels from left ?
  243.                 bpl.s    ham6_8a
  244.                 lsr.w    #1,D1              ;half error
  245. ham6_8a:        move.w   D1,_MaxError       
  246.                 move.w   D6,_MaxErrorPos
  247. ham6_9:         add.b    #1,D7              ;needed to get correct code
  248.                 tst.w    _ConvertMode       ;ConvertMode = 0  -> HAM6
  249.                 beq.s    ham6_10            ;ConvertMode != 0 -> HAM8
  250.                 IFD MC68020
  251.                   lsl.b    #2,D7            ;HAM8-adjust
  252.                 ELSE
  253.                   add.b    D7,D7            ;this is faster than shifting
  254.                   add.b    D7,D7            ;on the 68000
  255.                 ENDC
  256. ham6_10:        lsl.b    #4,D7              ;HAM6-adjust                      
  257.                 or.b     D5,D7
  258.                 move.b   D7,(A6,D6.W)       ;store code in bitmap
  259.  
  260.                 addq.w   #1,D6              ;increase _offset_ham
  261.                 cmp.w    xsize(sp),D6       ;end of column ?
  262.                 bne      search_begin
  263.                 bra.s    search_end
  264.  
  265. _search_finish: move.w   A3,D0              ;move error to D0
  266.                 cmp.w    #2,D6              ;less then 2 pixels from left ?
  267.                 bpl.s    _search_finish1
  268.                 lsr.w    #1,D0              ;half error
  269. _search_finish1: cmp.w    _MaxError,D0      ;compare with absolute max error
  270.                 ble.s    _search_finish2
  271.                 move.w   D0,_MaxError
  272.                 move.w   D6,_MaxErrorPos
  273. _search_finish2: move.w   A0,D0
  274.                 move.l   ColorTable(sp),A2
  275.                 lea      -3(A2,D0.W),A3     ;load A3 with pointer to colors
  276.                 divu     #3,D0
  277.                 subq.w   #1,D0
  278.                 move.b   D0,0(A6,D6.W)      ;store colornumber in bitmap
  279.                 lea      _blue_left,A2
  280.                 IFD MC68020
  281.                   move.l   (A3),(A2)
  282.                 ELSE
  283.                   move.b   (A3)+,(A2)+      ;store new left colors
  284.                   move.b   (A3)+,(A2)+      ;A3 may not be word aligned
  285.                   move.b   (A3)+,(A2)+      ;
  286.                 ENDC
  287.                 addq.w   #1,D6              ;increase _offset_ham
  288.                 cmp.w    xsize(sp),D6       ;have we reached the end ?
  289.                 bne      search_begin
  290.  
  291. search_end:     movem.l  (A7)+,D2-D7/A2-A3/A5/A6  ;restore registers
  292.                 rts                         ;jump back to caller
  293.                 
  294.  
  295.  
  296. ;we jump here if we have reached error 0 by colortable only
  297. ;and there was not a cache hit
  298. search5:        move.w   A0,D0         
  299.                 movea.l  _ColorCache,A2
  300.                 move.l   _CacheOffset,D1
  301.                 move.b   D0,0(A2,D1.l)      ;store the value in the cache                
  302.                 bra.s    _search_finish
  303.  
  304.  
  305. ;we jump here if we have a cache hit
  306. ;D1 contains the best color number, but we have to compute the error
  307.  
  308. _hit:           subq.w   #3,D1              ;correct color number
  309.                 move.w   D1,D7
  310.                 bsr.s    _compute_error
  311.         move.w   D1,A3              ;D1 is smaller than A3, store it
  312.                 move.w   D7,A0              ;store color number     
  313.                 bra      start_ham6         ;continue with HAM encoding
  314.  
  315.  
  316. ;compute the error
  317.  
  318.  
  319. _compute_error: moveq.l  #0,D1
  320.                 moveq.l  #0,D0             
  321.                 move.b   D2,D0              ;load blue_origin
  322.                 sub.b    0(A2,D7.W),D0      ;D0 = blue_color - blue_origin
  323.                 ext.w    D0                 ;extend result to word
  324.                 IFD MC68020
  325.                   add.w    0(A1,D0.W*2),D1
  326.                 ELSE
  327.                   add.w    D0,D0            
  328.                   add.w    0(A1,D0.W),D1    ;D1 = D1 + D0*D0
  329.                 ENDC
  330.                 addq.w   #1,D7              ;advance color table offset
  331.                 move.b   D3,D0              ;load red_origin
  332.                 sub.b    0(A2,D7.W),D0      ;D0 = red_color - red_origin
  333.                 ext.w    D0
  334.                 IFD MC68020
  335.                   add.w    0(A1,D0.W*2),D1
  336.                 ELSE
  337.                   add.w    D0,D0
  338.                   add.w    0(A1,D0.W),D1
  339.                 ENDC
  340.                 addq.w   #1,D7              ;advance color table offset
  341.                 move.b   D4,D0              ;load green_origin
  342.                 sub.b    0(A2,D7.W),D0      ;D0 = green_color - green_origin
  343.                 ext.w    D0
  344.                 IFD MC68020
  345.                   add.w    0(A1,D0.W*2),D1  ;D1 = D1 + D0*D0
  346.                 ELSE
  347.                   add.w    D0,D0
  348.                   add.w    0(A1,D0.W),D1
  349.                 ENDC
  350.                 addq.w   #1,D7              ;advance color table offset
  351.         rts
  352.  
  353.                 
  354.  
  355.  
  356.  
  357.  
  358. ;now comes the brute-force colormap search code
  359. ;if you know how to make it faster/smaller please let me know
  360.  
  361. ;the 68020 main loop is only 56 bytes long, it should 
  362. ;fit completely into the 256 bytes instruction cache of the 68020
  363. ;or 68030 processor
  364.  
  365. ;NOTE: this is a bit different compared to the HAM-code because
  366. ;signed 8 bit math gives wrong results with values higher than 127
  367. ;it computes the differences therefore with 16 bit
  368.  
  369. ;the maximum error value is 3*255^2=195075, we will therefore need
  370. ;32 bit arithmetic for the summation
  371.  
  372. ;register usage:
  373. ;                 D0 = general purpose register, return value
  374. ;                 D1 = contains error
  375. ;                 D2 = r1
  376. ;                 D3 = g1
  377. ;                 D4 = b1
  378. ;                 D5 = holds color from colormap
  379. ;                 D6 = counter
  380. ;                 D7 = color table offset
  381. ;                 A1 = pointer to multiplication table
  382. ;                 A2 = pointer to colormap
  383. ;                 A3 = smallest error
  384. ;                 A5 = actual error
  385. ;                 A6 = NColors
  386.  
  387. _MapColorASM:   movem.l D2-D7/A2-A3/A5/A6,-(A7)  ;store registers
  388.                 move.l  colormap(sp),A2
  389.                 move.l  NColors(sp),A6
  390.                 lea     _Mult_Table32,A1
  391.                 lea     255*4(A1),A1
  392.                 moveq.l #0,D2               ;ensure that the higher bytes
  393.                 moveq.l #0,D3               ;of these registers are cleared
  394.                 moveq.l #0,D4  
  395.                 move.b  r1(sp),D2
  396.                 move.b  g1(sp),D3
  397.                 move.b  b1(sp),D4
  398.                 move.l  #2000000000,A3      ;dummy value for min. error 
  399.                 moveq.l #0,D6               ;initialize counter
  400.                 moveq.l #0,D7
  401.                 moveq.l #0,D5
  402.  
  403. ;now comes the main loop
  404.  
  405. Map_start:      suba.l   A5,A5              ;clear A5 (actual error)
  406.                 move.l   D2,D0              ;load r1
  407.                 move.b   0(A2,D7.W),D5      ;load colormap.red
  408.                 sub.w    D5,D0              ;D0 = colormap.red - r1
  409.                 IFD MC68020
  410.                   add.l    0(A1,D0.W*4),A5
  411.                 ELSE
  412.                   lsl.w    #2,D0            
  413.                   add.l    0(A1,D0.W),A5    ;A5 = A5 + D0*D0
  414.                 ENDC
  415.                 move.l   D3,D0              ;load g1
  416.                 move.b   1(A2,D7.W),D5      ;load colormap.green
  417.                 sub.w    D5,D0              ;D5 = colormap.green - g1
  418.                 IFD MC68020
  419.                   add.l    0(A1,D0.W*4),A5
  420.                 ELSE
  421.                   lsl.w    #2,D0
  422.                   add.l    0(A1,D0.W),A5
  423.                 ENDC
  424.                 move.l   D4,D0              ;load b1
  425.                 move.b   2(A2,D7.W),D5      ;load colormap.blue
  426.                 sub.w    D5,D0              ;D0 = colormap.blue - b1
  427.                 IFD MC68020               
  428.                   add.l    0(A1,D0.W*4),A5  ;A5 = A5 + D0*D0
  429.                 ELSE
  430.                   lsl.w    #2,D0
  431.                   add.l    0(A1,D0.W),A5
  432.                 ENDC
  433.                 addq.w   #8,D7              ;advance color table offset              
  434.               
  435.                 cmp.l    A5,A3              ;A3 - A5 ?
  436.                 bls.s    Map1
  437.                 move.l   A5,A3              ;D1 is smaller than A3, store it
  438.                 move.w   D6,A0              ;store color number     
  439.                 move.l   A5,D0              ;do we have the correct color ?
  440.                 beq.s    Map_finish         ;then finish immediately
  441. Map1:           addq.w   #1,D6              ;advance color number
  442.                 cmp.l    A6,D6              ;have we reached highest colornum ?
  443.                 bne.s    Map_start          ;no, then once again                                               
  444. Map_finish:     move.l   A0,D0              ;store return value
  445.                 movem.l  (A7)+,D2-D7/A2-A3/A5/A6  ;restore registers
  446.                 rts                         ;jump back to caller
  447. end
  448.  
  449.